use crate::map::{MapNode, Path};

use std::ops::Add;
use std::sync::Arc;

const PL: usize = 2;

#[derive(Debug, Clone)]
pub struct Life {
    path: Path,
}

impl Life {
    pub fn new(path: Path) -> Life {
        Life { path }
    }
    pub fn fitness(&self) -> f64 {
        self.path.get_distance()
    }
    pub fn get_path(&self) -> &Path {
        &self.path
    }
    pub fn mutation(&mut self) {
        log::trace!("{:?} 突变", self);
        use rand::Rng;

        let len = self.path.get_raw().len();
        let mut rng = rand::thread_rng();
        let a1 = rng.gen_range(0..len);
        let mut a2 = rng.gen_range(0..len);
        while a1 == a2 {
            a2 = rng.gen_range(0..len);
        }
        self.path.swap(a1, a2);
    }
}

impl Add for &Life {
    type Output = Life;

    fn add(self, other: Self) -> Self::Output {
        log::trace!("{:?} 和 {:?} 交合", self, other);
        use rand::seq::SliceRandom;
        use std::collections::VecDeque;

        let self_path = self.get_path().get_raw();
        let other_path = other.get_path().get_raw();
        let mut result_path: Vec<Arc<MapNode>> = vec![];

        if self_path.len() != other_path.len() {
            panic!("两个生命体拥有不同的基因长度");
        }

        let len = self_path.len();

        let mut visited: Vec<bool> = vec![];
        let mut first_used: Vec<bool> = vec![];
        visited.resize(len, false);
        first_used.resize(len, false);

        // TODO: Change this block to fun or closer
        {
            let mut numbers: Vec<usize> = (0..len).collect();
            let mut rng = rand::thread_rng();
            numbers.shuffle(&mut rng);
            for i in 0..len / PL {
                first_used[numbers[i]] = true;
                visited[self_path[numbers[i]].get_id() as usize] = true;
            }
        };

        let mut other_queue = VecDeque::new();
        for i in 0..len {
            if !visited[other_path[i].get_id() as usize] {
                other_queue.push_back(Arc::clone(&other_path[i]));
            }
        }
        for i in 0..len {
            if first_used[i] {
                result_path.push(Arc::clone(&self_path[i]));
            } else {
                result_path.push(other_queue.pop_front().unwrap());
            }
        }

        Life::new(Path::new(result_path))
    }
}
